package org.ru.mse10.cvis.web.bean.action.search.datamodel;

import javax.faces.context.FacesContext;

import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
import org.ajax4jsf.model.Range;
import org.ajax4jsf.model.SequenceRange;
import org.ru.mse10.cvis.dto.BaseDTO;
import org.ru.mse10.cvis.entity.misc.Identity;
import org.ru.mse10.cvis.service.EntityService;
import org.ru.mse10.cvis.service.search.EntitySearcher;

/**
 * The Class JPADataModel.
 * 
 * @param <Z>
 *            the generic type
 * @param <T>
 *            the generic type
 * @param <M>
 *            the generic type
 */
public abstract class JPADataModel<Z extends EntityService, T extends Identity, M extends BaseDTO<T>>
		extends ExtendedDataModel<T> {

	/** The row key. */
	private Object rowKey;

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.model.ExtendedDataModel#setRowKey(java.lang.Object)
	 */
	@Override
	public void setRowKey(Object key) {
		rowKey = key;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ajax4jsf.model.ExtendedDataModel#getRowKey()
	 */
	@Override
	public Object getRowKey() {
		return rowKey;
	}

	/**
	 * Gets the searcher.
	 * 
	 * @return the searcher
	 */
	public abstract EntitySearcher<T, M> getSearcher();

	/**
	 * Gets the service.
	 * 
	 * @return the service
	 */
	public abstract Z getService();

	/**
	 * Gets the dto.
	 * 
	 * @return the dto
	 */
	public abstract M getDto();

	/**
	 * Gets the entity class.
	 * 
	 * @return the entity class
	 */
	public abstract Class<T> getEntityClass();

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.ajax4jsf.model.ExtendedDataModel#walk(javax.faces.context.FacesContext
	 * , org.ajax4jsf.model.DataVisitor, org.ajax4jsf.model.Range,
	 * java.lang.Object)
	 */
	@Override
	public void walk(FacesContext context, DataVisitor visitor, Range range,
			Object argument) {
		SequenceRange sequenceRange = (SequenceRange) range;
		getDto().setFirstResult(sequenceRange.getFirstRow());
		getDto().setMaxResults(sequenceRange.getRows());

		getService().search(getSearcher(), getDto(), false);
		for (T t : getDto().getResult()) {
			visitor.process(context, t.getId(), argument);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.faces.model.DataModel#isRowAvailable()
	 */
	@Override
	public boolean isRowAvailable() {
		return rowKey != null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.faces.model.DataModel#getRowCount()
	 */
	@Override
	public int getRowCount() {
		return getDto().getTotalNumberOfRows();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.faces.model.DataModel#getRowData()
	 */
	@Override
	public T getRowData() {
		return getService().find(getEntityClass(), (Long) getRowKey());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.faces.model.DataModel#getRowIndex()
	 */
	@Override
	public int getRowIndex() {
		return -1;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.faces.model.DataModel#setRowIndex(int)
	 */
	@Override
	public void setRowIndex(int rowIndex) {
		throw new UnsupportedOperationException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.faces.model.DataModel#getWrappedData()
	 */
	@Override
	public Object getWrappedData() {
		throw new UnsupportedOperationException();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.faces.model.DataModel#setWrappedData(java.lang.Object)
	 */
	@Override
	public void setWrappedData(Object data) {
		throw new UnsupportedOperationException();
	}

	/**
	 * Gets the id.
	 * 
	 * @param t
	 *            the t
	 * @return the id
	 */
	protected Object getId(T t) {
		return t.getId();
	}

}
